home *** CD-ROM | disk | FTP | other *** search
- #if !defined TSTREAM_H
- #define TSTREAM_H
-
- #include <iostream.h> // for base class definitions
-
- // class tbuf<>. Derived publicly from streambuf to
- // allow class ios which contains pointer to streambuf
- // access to virtual functions. tbuf<> implements
- // basic buffering, reading, writing and seeking on
- // a stream. It also provides open, close, attach,
- // and utility functions.
- template <class T>
- class tbuf : public streambuf {
- public:
- // openProtection provides a default parameter to the
- // open functions to specify what protection a file
- // will be created with. You can ignore this if it is
- // not necessary
- static const int openProtect;
- // tbufSize specifies the default buffer size. It is
- // set to 516 bytes.
- static const int tbufSize;
- // Default contructor. Make a buffer without a
- // stream attached. mode has a dual meaning, if it
- // is zero it means that any operation is allowable,
- // and the stream should not be deleted when closing.
- tbuf()
- : stream(0), mode(0), opened(0)
- {
- makbuf();
- }
- // create buffer and attach to t. t is assumed to be
- // already opened in read/write mode. t will not be
- // deleted or closed when closing this buffer
- tbuf(T &t)
- : stream(&t), mode(0), opened(1)
- {
- makbuf();
- }
- // create buffer from parameters, and attach to t.
- tbuf(T &t, char* b, int l)
- : stream(&t), mode(0), opened(1)
- {
- setbuf(b, l);
- }
- // destroy buffer. If mode is not zero, t will be
- // closed and deleted. Otherwise just flush the
- // output buffer.
- ~tbuf()
- {
- if(mode)
- close();
- else
- overflow(EOF);
- }
- // return open status
- int is_open() const
- {
- return opened;
- }
- // return reference to stream
- T &fd() const
- {
- return *stream;
- }
- // open stream. mode must not be zero. stream will
- // be closed and deleted when closing buffer.
- tbuf *open(const char *name, int mode,
- int prot = tbuf::openProtect);
- // close buffer and optionally delete stream.
- tbuf *close();
- // attach stream to buffer. Stream is assumed to
- // be opened in read/write mode.
- tbuf *attach(T &);
- // write buffer to stream and reset pointers.
- virtual int overflow(int = EOF);
- // read data into buffer and reset pointers.
- virtual int underflow();
- // sync input and output.
- virtual int sync();
- // seek to offset and flush output buffers.
- virtual long seekoff(long, ios::seek_dir, int);
- // set buffer. For unbuffered i/o set char * to 0.
- virtual streambuf *setbuf(char *, int);
- protected:
- int putBackSize()
- {
- return (blen() > 8) ? 4 : 1;
- }
- void resetpg(int end = 0);
- void makbuf()
- {
- setbuf(new char[tbufSize], tbufSize);
- }
- int unbuffered()
- {
- return streambuf::unbuffered() | !base();
- }
- T *stream;
- int mode;
- short opened;
- char lookAhead[2];
- };
-
- template <class T>
- const int tbuf<T>::tbufSize = 516;
- template <class T>
- const int tbuf<T>::openProtect = 0;
-
- // Attach an open stream to this buffer. When this
- // buffer is closed don't try to close stream. If
- // not yet buffered, try to create a buffer. Reset
- // the put and get pointers. Return 0 on error, or
- // this if OK.
- template <class T>
- tbuf<T>* tbuf<T>::attach(T &t)
- {
- if(opened) // if already opened, return 0
- return 0;
- stream = &t; // attach stream.
- opened = 1; // set to opened.
- mode = 0; // buffer doesn't own stream.
- if(!base()) // if no buffer yet...
- makbuf(); // try to make one.
- else
- resetpg(); // reset put and get pointers.
- return this;
- }
-
- // Close buffer, and optionally stream attached to it.
- // Flush buffer if data inside. Return 0 on error or
- // this if OK.
- template <class T>
- tbuf<T>* tbuf<T>::close()
- {
- if(!*stream) // if stream closed,
- opened = 0; // set opened off.
- if(!opened) // if not on return 0.
- return 0;
- int ret = 0;
- if(out_waiting()) // if output in buffer.
- // flush output buffer.
- ret = (overflow(EOF) == EOF) ? 1 : 0;
- if(mode) // if mode is 0, don't
- delete stream; // close or delete stream.
- opened = 0; // set opened off.
- return ret ? 0 : this;
- }
-
- // Write data from buffer to stream. This function
- // is called when the buffer is full and we need to
- // output more characters. The parameter c is the
- // character that caused the overflow. If the
- // stream is buffered, it will be placed in the
- // buffer, otherwise it is written to the stream.
- // If input char is EOF, don't write, just flush.
- // Returns EOF on error, or 1 on success.
- template <class T>
- int tbuf<T>::overflow(int c)
- {
- if(!opened || // check to see if stream
- mode == 0 || // is on and mode is out.
- !(mode&ios::out))
- return EOF;
- if(unbuffered())
- {
- if(c != EOF)
- { // if unbuffered,
- char b = c; // write single char
- if(stream->write(&b, 1) != 1)
- return EOF;
- }
- }
- else // else if buffered.
- {
- if(sync() != 0) // sync input and output
- return EOF; // when writing
- resetpg(1); // reset the put/get pointers
- if(c != EOF)
- {
- sputc(c); // add c to the buffer
- gbump(1); // move the get pointer
- }
- }
- return 1; // return OK
- }
-
- // Open stream. If mode ios::ate (at end) is on,
- // seek to end
- template <class T>
- tbuf<T>* tbuf<T>::open(const char* n, int m, int p)
- {
- if(opened || !m) // if already on, or no mode,
- return 0; // return error.
- stream = new T; // make new stream pointer.
- stream->open(n, m, p);// open stream.
- if(!*stream) // if stream not open,
- return 0; // return error.
- opened = 1; // set to on.
- mode = m; // remeber mode.
- if((mode & ios::ate) &&
- stream->seek(0L, ios::end) == EOF)
- return 0; // seek to end if ios::ate.
- resetpg(); // reset put/get pointers.
- return this; // return OK.
- }
-
- // Set the buffer, reset the put/get pointers.
- // Return 0 on error, this if OK.
- template <class T>
- streambuf* tbuf<T>::setbuf(char* b, int l)
- {
- if(!b) // turn off buffering.
- {
- streambuf::unbuffered(1);
- return this;
- }
- if(opened && base())// check if stream is opened,
- return 0; // , and no buffer yet.
- setb(b, b+l, 0); // set buffer pointers.
- resetpg(); // reset put/get pointers.
- return this; // return OK.
- }
-
- // Seek to offset. dir indicates the relativity of
- // the offset, ethier from beginning, current postion,
- // or end (ios::beg, ios::cur, ios::end).
- // First make sure there's nothing in the buffer.
- template <class T>
- long tbuf<T>::seekoff(long off, ios::seek_dir dir,
- int /* mode ignored */)
- {
- long loff = off;
- int count = out_waiting(); // flush output first.
- if(count)
- {
- if(stream->write(pbase(), count) != count)
- return EOF;
- }
- else if(dir == ios::cur && // if relative seek,
- (count = in_avail()) != 0)
- loff -= count; // discount input.
- resetpg(); // reset pointers.
- return stream->seek(loff, dir);
- }
-
- // sync input and output buffer pointers. If output
- // is waiting, write it, if input is waiting,
- // back up to read it again
- template <class T>
- int tbuf<T>::sync()
- {
- if (!opened) // check if opened.
- return EOF;
- int count = out_waiting(); // check for output,
- if(count) // in buffer.
- {
- if(stream->write(pbase(), count) != count)
- return EOF; // write output.
- resetpg(1);
- }
- else if(in_avail()) // check for input
- { // in buffer
- long pos = stream->seek(long(-in_avail()),
- ios::cur);
- setg(eback(), gptr(), gptr());
- setp(gptr(), gptr()); // set up to re-read.
- if(pos == EOF)
- return EOF;
- }
- return 0;
- }
-
- // Read from stream to fill buffer. Must be opened and
- // in input mode. If there is input in the buffer,
- // return it. Otherwise call sync, read from stream,
- // and set pointers. If the input is unbuffered,
- // use the lookahead buffer.
- template <class T>
- int tbuf<T>::underflow()
- {
- if(!opened || mode == 0 || !(mode&ios::in))
- return EOF; // check for correct mode.
- if(in_avail()) // if available from buffer,
- return *gptr()&0xFF; // don't bother.
- int c;
- int count;
- if(unbuffered()) // if unbuffered.
- {
- count = stream->read(lookAhead, 1);
- if(count == EOF) // read one char
- { // into look ahead
- c = EOF; // buffer.
- setg(0, 0, 0);
- }
- else
- {
- c = lookAhead[0]&0xFF;
- setg(lookAhead, lookAhead, lookAhead+1);
- }
- }
- else // else buffered.
- {
- if(sync() != 0) // sync pointers.
- return EOF;
- int pb = putBackSize();
- char *b = base(); // read into buffer.
- count = stream->read(b+pb, blen()-pb);
- if(count == EOF) // check read return.
- return EOF;
- setg(b, b+pb, b+pb+count);
- setp(b+pb, b+pb); // set pointers.
- if(count) // return first char.
- c = *gptr()&0xFF;
- }
- if(!count)
- c = EOF;
- return c;
- }
-
- // reset the put and get pointers. If end is
- // true set the end pointers to the end of
- // the buffer.
- template<class T>
- void tbuf<T>::resetpg(int end)
- {
- char *buf = base(); // get the start of buffer.
- char *sbuf = buf + (buf ? putBackSize() : 0);
- char *ebuf; // set start and end pointers.
- if(end)
- ebuf = buf + blen();
- else
- ebuf = sbuf;
- setp(sbuf, ebuf); // set put pointer
- setg(buf, sbuf, sbuf);// set get pointer
- }
-
- // tstreambase is virtually derived from ios. ios
- // does not define any functionality for tstreambase
- // but allows communication between tstreambase and
- // istream, ostream and stream classes. The functions
- // defined in tstreambase typically call the same
- // named function for its tbuf<> member and set ios
- // status flags. When a tstreambase is constructed
- // ios is initialized with a pointer to the tbuf<>
- // member. ios see this pointer as a streambuf
- // pointer, and only has access to tbuf<> through the
- // virtual functions, overflow, underflow, sync, and
- // seekoff.
- template <class T>
- class tstreambase : virtual public ios {
- public:
- // Default constructor. Make an unattached
- // buffer, and initialize ios with it's pointer.
- tstreambase()
- : tbbuf()
- {
- ios::init(&tbbuf);
- }
- // Make a buffer attach to named stream, and open
- // stream
- tstreambase(const char* n, int m,
- int p = tbuf<T>::openProtect)
- : tbbuf()
- {
- ios::init(&tbbuf);
- open(n, m, p);
- }
- // Make a buffer attached to already opened stream.
- tstreambase(T &f)
- : tbbuf(f)
- {
- ios::init(&tbbuf);
- }
- // Make a buffer using parameters, and attach
- // to already opened stream.
- tstreambase(T &f, char* b, int l)
- : tbbuf(f, b, l)
- {
- ios::init(&tbbuf);
- }
- // Destroy buffer
- ~tstreambase()
- {
- ;
- }
- // close attached stream and set ios flags.
- void close()
- {
- if(tbbuf.close())
- clear(ios::goodbit);
- else
- setstate(ios::failbit);
- }
- // set buffer and set ios flags.
- void tstreambase::setbuf(char* b, int l)
- {
- if(tbbuf.setbuf(b, l))
- clear(ios::goodbit);
- else
- setstate(ios::failbit);
- }
- // open stream and set ios flags.
- void open(const char *, int,
- int = tbuf<T>::openProtect);
- // attach opened stream and set ios flags.
- void attach(T &);
- // return the buffer.
- tbuf<T> *rdbuf()
- {
- return &tbbuf;
- }
- private:
- tbuf<T> tbbuf;
- };
-
- // Attempt to open tbuf<>, and set ios flags
- // accordingly. Opening an already open stream
- // results in an error. If ios::app (append to
- // file) is set, also set ios::out. If ios::out
- // is set, and ios::app, ios::in, and ios::ate
- // (start at end) are not set, set the ios::trunc bit.
- template <class T>
- void tstreambase<T>::open(const char *n, int m, int p)
- {
- if(m & ios::app)
- m |= ios::out;
- else if((m & (ios::out|ios::ate|ios::app|ios::in))
- == ios::out)
- m |= ios::trunc;
- if(tbbuf.is_open())
- clear(ios::failbit);
- else if(tbbuf.open(n, m, p))
- clear(ios::goodbit);
- else
- clear(ios::badbit);
- }
-
- // Attach an opened stream to buffer, and set the ios
- // bits accordingly.
- template <class T>
- void tstreambase<T>::attach(T &f)
- {
- if(tbbuf.is_open())
- setstate(ios::failbit);
- else if(tbbuf.attach(f))
- clear(ios::goodbit);
- else
- clear(ios::badbit);
- }
-
- // The itstream, otstream and tstream class are merely
- // "shell" classes, and serve only to combine the
- // functionality of it's base class. The only functions
- // defined are the constructor and destructors, and
- // open and rdbuf. There are no addition data members
- // and all functions call directly the functions of the
- // base class. The default open mode is ios::in for
- // itstream, ios::out for otstream, and both for
- // tstream.
- template <class T>
- class itstream : public tstreambase<T>,
- public istream {
- public:
- itstream()
- {
- ;
- }
- itstream(const char* n, int m = ios::in,
- int p = tbuf<T>::openProtect)
- : tstreambase<T>(n, m | ios::in, p)
- {
- ;
- }
- itstream(T &f)
- : tstreambase<T>(f)
- {
- ;
- }
- itstream(T &f, char* b, int l)
- : tstreambase<T>(f, b, l)
- {
- ;
- }
- ~itstream()
- {
- ;
- }
- tbuf<T> *rdbuf()
- {
- return tstreambase<T>::rdbuf();
- }
- void open(const char *n, int m = ios::in,
- int p = tbuf<T>::openProtect)
- {
- tstreambase<T>::open(n, m | ios::in, p);
- }
- };
-
- template <class T>
- class otstream : public tstreambase<T>,
- public ostream {
- public:
- otstream()
- {
- ;
- }
- otstream(const char* n, int m = ios::out,
- int p = tbuf<T>::openProtect)
- : tstreambase<T>(n, m | ios::out, p)
- {
- ;
- }
- otstream(T &f)
- : tstreambase<T>(f)
- {
- ;
- }
- otstream(T &f, char* b, int l)
- : tstreambase<T>(f, b, l)
- {
- ;
- }
- ~otstream()
- {
- ;
- }
- tbuf<T> *rdbuf()
- {
- return tstreambase<T>::rdbuf();
- }
- void open(const char *n, int m = ios::out,
- int p = tbuf<T>::openProtect)
- {
- tstreambase<T>::open(n, m | ios::out, p);
- }
- };
-
- template <class T>
- class tstream : public tstreambase<T>,
- public iostream {
- public:
- tstream()
- {
- ;
- }
- tstream(const char *n, int m,
- int p = tbuf<T>::openProtect)
- : tstreambase<T>(n, m, p)
- {
- ;
- }
- tstream(T &f)
- : tstreambase<T>(f)
- {
- ;
- }
- tstream(T &f, char *b, int l)
- : tstreambase<T>(f, b, l), iostream()
- {
- ;
- }
- ~tstream()
- {
- ;
- }
- tbuf<T> *rdbuf()
- {
- return tstreambase<T>::rdbuf();
- }
- void open(const char *n, int m,
- int p = tbuf<T>::openProtect)
- {
- tstreambase<T>::open(n, m, p);
- }
- };
-
- #endif
-
-